package com.wteam.modules.system.config;

import lombok.RequiredArgsConstructor;
import org.springframework.amqp.core.*;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Scope;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

@Configuration
@RequiredArgsConstructor
public class RabitMqConfig {

    private static ConcurrentMap<String, String > selectCourseResult = new ConcurrentHashMap<>();

    public static void setResult(String id, String result){
        selectCourseResult.put(id,result);
    }

    public static String getResult(String id){
//        String result = selectCourseResult.get(id);
//        selectCourseResult.remove(id);
        return selectCourseResult.get(id);
    }

    public static void remove(String id){
        selectCourseResult.remove(id);
    }

    @Value("${spring.rabbitmq.exchangeName2}")
    private String exchangeName;
    @Value("${spring.rabbitmq.queueName.selectCourseQueue1}")
    private String selectCourseQueue1Name;
    @Value("${spring.rabbitmq.queueName.selectCourseQueue2}")
    private String selectCourseQueue2Name;
    @Value("${spring.rabbitmq.routeKey.selectCourseKey1}")
    private String selectCourseRouteKey1;
    @Value("${spring.rabbitmq.routeKey.selectCourseKey2}")
    private String selectCourseRouteKey2;
//    @Value("${spring.rabbitmq.queueName.replyQueue1}")
//    private String replyQueue1Name;


    @Bean
    @Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
        final RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        rabbitTemplate.setMessageConverter(messageConverter());
        rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
            if (!ack) {
                System.out.println("HelloSender消息发送失败" + cause + correlationData.toString());
                setResult(correlationData.getId(),cause);
            } else {
                System.out.println("HelloSender 消息发送成功 ");
                setResult(correlationData.getId(),"1");
            }
        });
        return rabbitTemplate;
    }

    /**
     * 创建选课队列1
     *
     * @return
     */
    @Bean
    public Queue selectCourseQueue1() {
        Map<String, Object> arguments = new HashMap<>();
        //镜像队列将会在整个集群中复制。当一个新的节点加入后，也会在这个节点上复制一份
        //arguments.put("x-ha-policy", "all");
        //队列的最大长度，超过指定长度将会把最早的几条删除掉
        arguments.put("x-max-length", 100000);
        //队列最大占用的空间大小，当达到最大值是会删除之前的数据腾出空间
        arguments.put("x-max-length-bytes", 10000000);
        //参数2 durable：是否持久化。队列的声明默认是存放到内存中的，如果rabbitmq重启会丢失，如果想重启之后还存在就要使队列持久化，保存到Erlang自带的Mnesia数据库中，当rabbitmq重启之后会读取该数据库
        //参数3 exclusive：是否排外的。有两个作用，一：当连接关闭时connection.close()该队列是否会自动删除；二：该队列是否是私有的private，如果不是排外的，可以使用两个消费者都访问同一个队列，没有任何问题，如果是排外的，会对当前队列加锁，其他通道channel是不能访问的
        //参数4 autoDelete：是否自动删除。当最后一个消费者断开连接之后队列是否自动被删除，可以通过RabbitMQ Management，查看某个队列的消费者数量，当consumers = 0时队列就会自动删除
        return new Queue(selectCourseQueue1Name, false, false, false, arguments);

    }

    /**
     * 创建选课队列2
     *
     * @return
     */
    @Bean
    public Queue selectCourseQueue2() {
        Map<String, Object> arguments = new HashMap<>();
        //镜像队列将会在整个集群中复制。当一个新的节点加入后，也会在这个节点上复制一份
        //arguments.put("x-ha-policy", "all");
        //队列的最大长度，超过指定长度将会把最早的几条删除掉
        arguments.put("x-max-length", 100000);
        //队列最大占用的空间大小，当达到最大值是会删除之前的数据腾出空间
        arguments.put("x-max-length-bytes", 10000000);
        //参数2 durable：是否持久化。队列的声明默认是存放到内存中的，如果rabbitmq重启会丢失，如果想重启之后还存在就要使队列持久化，保存到Erlang自带的Mnesia数据库中，当rabbitmq重启之后会读取该数据库
        //参数3 exclusive：是否排外的。有两个作用，一：当连接关闭时connection.close()该队列是否会自动删除；二：该队列是否是私有的private，如果不是排外的，可以使用两个消费者都访问同一个队列，没有任何问题，如果是排外的，会对当前队列加锁，其他通道channel是不能访问的
        //参数4 autoDelete：是否自动删除。当最后一个消费者断开连接之后队列是否自动被删除，可以通过RabbitMQ Management，查看某个队列的消费者数量，当consumers = 0时队列就会自动删除
        return new Queue(selectCourseQueue2Name, false, false, false, arguments);

    }

//    @Bean
//    public Queue replyQueue1(){
//        return new Queue(replyQueue1Name);
//    }

    /**
     * 创建交换机
     *
     * @return
     */
    @Bean
    public TopicExchange defaultExchange() {
        //参数2 是否持久化，默认  true
        //参数3 是否自动删除，默认false。为true时，broker关闭，将删除，并且可以通过关闭和重新打开连接来重新声明它。
        return new TopicExchange(exchangeName, false, true);
    }

    @Bean
    public FanoutExchange fanoutExchange(){
        return new FanoutExchange("fanout",false,true);
    }

    /**
     * 按照路由规则绑定队列和交换机，使交换机中的消息能够发送到指定队列中
     *
     * @return
     */
    @Bean
    public Binding selectCourseBinding1() {
        return BindingBuilder.bind(selectCourseQueue1())
                .to(defaultExchange())
                .with(selectCourseRouteKey1);
    }
    @Bean
    public Binding selectCourseBinding2() {
        return BindingBuilder.bind(selectCourseQueue2())
                .to(defaultExchange())
                .with(selectCourseRouteKey2);
    }

    @Bean
    public Binding bindAll1(){
        return BindingBuilder.bind(selectCourseQueue1()).to(fanoutExchange());
    }
    @Bean
    public Binding bindAll2(){
        return BindingBuilder.bind(selectCourseQueue2()).to(fanoutExchange());
    }


//    @Bean
//    public Binding replyQueueBinding1(){
//        return BindingBuilder.bind(replyQueue1())
//                .to(defaultExchange())
//                .with(replyQueue1Name);
//    }

    @Bean
    public MessageConverter messageConverter(){
        return new Jackson2JsonMessageConverter();
    }




}
